# encoding=utf-8
# pip install pyserial -i https://pypi.tuna.tsinghua.edu.cn/simple
# Connect:
#    B- --> B-
#    A+ --> A+
#   GND --> GND

import time
import traceback
import logging
from datetime import datetime
from SerialBase import SerialBase
from SerialTools import *

# logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')


class SerialRecv(SerialBase):
    def __init__(self, device: str, rate: int = 115200, package_size: int = 64):
        super().__init__(device, rate)

        # size for one frame
        self.package_size = package_size
        self.body_size = self.package_size - 6 - 1

    def recv_raw_file(self, save_path: str):
        array_list = []
        next_package_index = 0

        while True:
            recv_data = self._try_recv_frame()
            if recv_data is None:
                return False

            package_index, data_len, frame_data = recv_data
            logging.info("next package is: {}, array_len: {}, recv: {}".format(
                next_package_index, len(array_list), package_index)
            )
            if (next_package_index == package_index) and (data_len != 0):
                next_package_index += 1

                # recv success
                array_list.extend(frame_data)
                if data_len != self.body_size:
                    # recv finish
                    with open(save_path, 'wb') as file:
                        decode_bytes = decompress_file(bytes(bytearray(array_list)))
                        file.write(decode_bytes)
                    return True
            else:
                self._send_raw_data(self.ERROR.to_bytes(1, 'big'))


    def _try_recv_frame(self):
        error_msg = ""
        for i in range(3):
            data = self._recv_one_frame()
            if data is not None:
                self._send_raw_data(self.ACK.to_bytes(1, 'big'))
                return data
            else:
                error_msg = "Recv data frame error"

            # time.sleep(0.1)

        logging.error(error_msg)
        return None


    def _recv_one_frame(self):
        b_array = []
        try:
            # 1: start signal
            signal = int.from_bytes(self._read_raw_data(1), 'big')
            if signal != 0x00:
                # send faster than recv
                self._send_raw_data(self.ERROR.to_bytes(1, 'big'))
                return None
            b_array.append(signal)

            # 2 - 5: package index
            package_index = 0
            for i in range(4):
                uint8 = int.from_bytes(self._read_raw_data(1), 'big')
                b_array.append(uint8)
                package_index += (uint8 << (8 * i))

            # 6: len
            data_len = int.from_bytes(self._read_raw_data(1), 'big')
            b_array.append(data_len)

            # 7 - buffer-1: data
            frame_data = bytearray(self._read_raw_data(data_len))
            frame_data = [b for b in frame_data]
            b_array.extend(frame_data)

            # buffer: crc
            recv_crc = int.from_bytes(self._read_raw_data(1), 'big')
            check_crc = self._crc8(b_array)
            if recv_crc != check_crc:
                self._send_raw_data(self.ERROR.to_bytes(1, 'big'))
                return None

            return package_index, data_len, frame_data
        except Exception as e:
            logging.error(traceback.format_exc())
            self._send_raw_data(self.ERROR.to_bytes(1, 'big'))
            return None


if __name__ == '__main__':
    import os
    device = SerialRecv("/dev/ttyACM1", 6000000, 256)
    date_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    status = device.recv_raw_file(date_time + ".jpg")
    print(os.path.getsize(date_time + ".jpg"))
